#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
int ticket = 100;
pthread_mutex_t mutex;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void *route(void *arg)
{
    //哪个线程
    char *id = (char *)arg;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        if (ticket > 0)
        {
            usleep(1000);
            printf("%s sells ticket:%d\n", id, ticket);
            ticket--;
            pthread_mutex_unlock(&mutex);
            // sched_yield(); 放弃CPU
        }
        else
        {
            printf("%s wait on cond!\n",id);
            //没有票就直接在条件变量下等待
            pthread_cond_wait(&cond,&mutex);//醒来的时候会重新加锁
        }
        pthread_mutex_unlock(&mutex);
    }
}
int main(void)
{
    pthread_t t1, t2, t3, t4;
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&t1, NULL, route, (void*)"thread 1");
    pthread_create(&t2, NULL, route, (void*)"thread 2");
    pthread_create(&t3, NULL, route, (void*)"thread 3");
    pthread_create(&t4, NULL, route, (void*)"thread 4");

    int cnt = 10;
    while(true)
    {
        //每隔五秒放一次票
        sleep(5);
        printf("主线程放票了");
        ticket+=cnt;
        //唤醒一个条件变量去抢票
        pthread_cond_signal(&cond);
    }
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);
    pthread_mutex_destroy(&mutex);
}

// 锁本身是全局的，那么锁也是共享资源
// 1. pthread_mutex：加锁和解锁被设置为原子的，---TODO
// 2. 如何看待锁呢？----二元信号量就是锁
//     2.1: 加锁本质就是对资源展开预定
//     2.2: 整体试用资源
// 3. 如果申请锁的时候，锁被别人拿走之后，怎么办？---其他线程必须阻塞等待
// 4. 线程在访问临界区代码的时候，可不可以切换？？---当然是可以切换的。
//     4.1: 我被切走的时候，别人能进来吗？----因为还没有解锁---这不就是串行吗----效率低的原因（原子性）
// 5. 不遵守这个约定？？----是可以的----这就是程序的bug
// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//谁保护锁的安全，锁也是共享资源
//  int ticketnum = 10000;//共享资源，临界资源

// class ThreadData
// {
// public:
//     string name;//线程名称
//     pthread_mutex_t *lock_ptr;//
// };

// void Tickt(ThreadData& td)
// {
//     while(true)
//     {
//         //加锁
//         pthread_mutex_lock(td.lock_ptr);
//         //这个代码叫做临界区
//         //有票数的时候才抢票
//         if(ticketnum > 0)
//         {
//             usleep(1000);
//             printf("get a new ticket id:%d,thread name is:%s\n",ticketnum--,td.name.c_str());
//             //入库
//             //usleep(1000);
//             pthread_mutex_unlock(td.lock_ptr);
//         }
//         //没有票了
//         else
//         {
//             pthread_mutex_unlock(td.lock_ptr);
//             break;
//         }
//         //解锁
//     }
// }

// int main()
// {
//     pthread_mutex_t lock;
//     pthread_mutex_init(&lock,nullptr);
//     //构建线程对象
//     vector<ThreadModule::Thread<ThreadData>> threads;
//     for(int i = 0;i < 5;i++)
//     {
//         //每个线程传递一个threaddata的对象
//         ThreadData * td = new ThreadData;
//         td->lock_ptr = &lock;
//         //这里因该是data，所以应该传递*td，而不是指针变量
//         threads.emplace_back(Tickt,*td);
//         //获取最后一个的名字
//         td->name = threads.back().Name();
//     }
//     //启动线程
//     for(auto &thread:threads)
//     {
//         thread.Start();
//     }

//     //等待线程
//     for(auto &thread:threads)
//     {
//         thread.Join();
//     }
//     pthread_mutex_destroy(&lock);
//     return 0;
// }